﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Reflection;
using Handrise.BasicModal.Serialization;
using ICSharpCode.SharpZipLib.Zip;

namespace Handrise.CDCable.Business
{
    /// <summary>
    /// 设备及标准数据同步
    /// </summary>
    public class StandardDataAndDeviceSynchronize
    {
        private ServerExchange serverExchange = new ServerExchange();

        /// <summary>
        /// 同步设备，最大同步100个数据
        /// </summary>
        /// <param name="tmpFileID">临时存放的设备文件ID</param>
        /// <param name="devicesBuffer">需要返回给PDA的设备通用对象列表流</param>
        /// <param name="deviceDetailsBuffer">需要返回给PDA的设备详情对象列表流</param>
        /// <param name="deviceDetailsBuffer">请求的开始点</param>
        /// <returns></returns>
        public bool SynchronizeDevice(string tmpFileID, out byte[] devicesBuffer,out byte[] deviceDetailsBuffer,int beginIndex)
        {
            try
            {
                bool deleteDevicesFile = false;
                bool deleteDeviceDetailsFile = false;

                CompactFormatterPlus cfp = new CompactFormatterPlus();

                string devicesFile = CommonFunction.GetLocalPath() + "\\Temp\\" + tmpFileID + ".d";
                FileStream fs = new FileStream(devicesFile, FileMode.Open);
                byte[] tmpBuffer = new byte[fs.Length];
                fs.Seek(0, SeekOrigin.Begin);
                fs.Read(tmpBuffer, 0, tmpBuffer.Length);
                fs.Close();

                //先获取该类型设备所有的数据
                List<Device> devices = (List<Device>)cfp.Deserialize(tmpBuffer);
                //获取100个数据或最后一批数据
                List<Device> returnDevices = new List<Device>();
                for (int i = 0; i < 100; i++)
                {
                    if (beginIndex + i >= devices.Count)
                    {
                        deleteDevicesFile = true;
                        break;
                    }
                    returnDevices.Add(devices[beginIndex+i]) ;
                }
                //设置返回的流
                devicesBuffer = cfp.Serialize(returnDevices);

                string deviceDetailsFile = CommonFunction.GetLocalPath() + "\\Temp\\" + tmpFileID + ".dd";
                fs = new FileStream(deviceDetailsFile, FileMode.Open);
                tmpBuffer = new byte[fs.Length];
                fs.Seek(0, SeekOrigin.Begin);
                fs.Read(tmpBuffer, 0, tmpBuffer.Length);
                fs.Close();

                //先获取该类型设备所有的详情数据
                List<Object> deviceDetails = (List<Object>)cfp.Deserialize(tmpBuffer);
                //获取100个数据或最后一批数据
                List<Object> returndeviceDetails = new List<Object>();
                for (int i = 0; i < 100; i++)
                {
                    if (beginIndex + i >= deviceDetails.Count)
                    {
                        deleteDeviceDetailsFile = true;
                        break;
                    }
                    returndeviceDetails.Add(deviceDetails[beginIndex + i]);
                }
                //设置返回的流
                deviceDetailsBuffer = cfp.Serialize(returndeviceDetails);

                //删除临时文件
                if(deleteDevicesFile)
                    File.Delete(devicesFile);
                if(deleteDeviceDetailsFile)
                    File.Delete(deviceDetailsFile);
                return true;
            }
            catch (Exception e)
            {
                
                throw new Exception("同步设备异常："+ e.Message);
            }
        }

        /// <summary>
        /// 同步标准数据
        /// </summary>
        /// <param name="tmpFileID"></param>
        /// <param name="buffer"></param>
        /// <param name="beginIndex"></param>
        /// <returns></returns>
        public bool SynchronizeStandardData(string tmpFileID, out byte[] buffer, int beginIndex)
        {
            try
            {
                bool deleteFile = false;

                CompactFormatterPlus cfp = new CompactFormatterPlus();

                string fileName = CommonFunction.GetLocalPath() + "\\Temp\\" + tmpFileID + ".s";
                FileStream fs = new FileStream(fileName, FileMode.Open);
                byte[] tmpBuffer = new byte[fs.Length];
                fs.Seek(0, SeekOrigin.Begin);
                fs.Read(tmpBuffer, 0, tmpBuffer.Length);
                fs.Close();

                //先获取该类型所有的标准数据
                List<Object> standardDatas = (List<Object>)cfp.Deserialize(tmpBuffer);
                //获取100个数据或最后一批数据
                List<Object> returnStandardDatas = new List<Object>();
                for (int i = 0; i < 100; i++)
                {
                    if (beginIndex + i >= standardDatas.Count)
                    {
                        deleteFile = true;
                        break;
                    }
                    returnStandardDatas.Add(standardDatas[beginIndex + i]);
                }
                //设置返回的流
                buffer = cfp.Serialize(returnStandardDatas);


                //删除临时文件
                if (deleteFile)
                    File.Delete(fileName);
                return true;
            }
            catch (Exception e)
            {

                throw new Exception("同步设备异常：" + e.Message);
            }
        }


        public bool SynchronizeDeviceGPSData(string tmpFileID, out byte[] buffer, int beginIndex)
        {
            try
            {
                bool deleteFile = false;

                CompactFormatterPlus cfp = new CompactFormatterPlus();

                string fileName = CommonFunction.GetLocalPath() + "\\Temp\\" + tmpFileID + ".g";
                FileStream fs = new FileStream(fileName, FileMode.Open);
                byte[] tmpBuffer = new byte[fs.Length];
                fs.Seek(0, SeekOrigin.Begin);
                fs.Read(tmpBuffer, 0, tmpBuffer.Length);
                fs.Close();

                //先获取所有的设备GPS数据
                List<DeviceGPS> gisDatas = (List<DeviceGPS>)cfp.Deserialize(tmpBuffer);
                //获取100个数据或最后一批数据
                List<DeviceGPS> returnGISDatas = new List<DeviceGPS>();
                for (int i = 0; i < 100; i++)
                {
                    if (beginIndex + i >= gisDatas.Count)
                    {
                        deleteFile = true;
                        break;
                    }
                    returnGISDatas.Add(gisDatas[beginIndex + i]);
                }
                //设置返回的流
                buffer = cfp.Serialize(returnGISDatas);


                //删除临时文件
                if (deleteFile)
                    File.Delete(fileName);
                return true;
            }
            catch (Exception e)
            {

                throw new Exception("同步设备异常：" + e.Message);
            }
        }


        /// <summary>
        /// 下载设备和标准数据到服务器的临时目录
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="eqpUpdateTime"></param>
        /// <returns></returns>
        public string DownloadStandardDataAndDevice(string userName, string eqpUpdateTime)
        {
            //下载标准数据和设备
           string receiveData = serverExchange.DownloadStandardDataAndDevice(userName, eqpUpdateTime);

            //处理数据
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(receiveData);
            //先尝试获取正确的返回结果
            XmlNode xnValue = CommonFunction.GetXmlNode(xmlDoc, "message/operation/returnValue/value");
            if (xnValue == null)
            {
                //没有正确的返回结果
                throw new Exception("主站系统返回数据异常");
            }
            //解压数据
            XmlDocument xmlZipData = new XmlDocument();
            xmlZipData.LoadXml(xnValue.InnerText);
            XmlNode xnZipData = CommonFunction.GetXmlNode(xmlZipData, "PDAPackageData/pdaPackageByte");
            if (xnZipData == null)
                return "";
            string dataStr = UnZipString(xnZipData.InnerText);
            XmlDocument xmlData = new XmlDocument();
            xmlData.LoadXml(dataStr);

            //获取对应的标准数据和设备的xml内容
            XmlNode xnStandrdDataAndDevice = CommonFunction.GetXmlNode(xmlData, "message/operation/returnValue/value");
            if(xnStandrdDataAndDevice == null)
                return "" ;
            XmlDocument xmlStandrdDataAndDevice = new XmlDocument();
            xmlStandrdDataAndDevice.LoadXml(xnStandrdDataAndDevice.InnerText);

            //处理正确的数据
            //处理设备和标准数据
            string reStr= AnalyseStandrdDataAndDevice(xmlStandrdDataAndDevice);
            //处理GIS数据
            string gisStr = AnalyseGISData(xmlStandrdDataAndDevice);
            if (reStr != "")
                reStr += ";" + gisStr;
            else
                reStr = gisStr;

            return reStr;

        }

        /// <summary>
        /// 分析标准数据和设备数据
        /// </summary>
        /// <returns></returns>
        private string AnalyseStandrdDataAndDevice(XmlDocument xmlData)
        {
            string re = "";

            //设置所有需要同步的实体
            List<Type> types = new List<Type>();
            types.Add(typeof(EM_Among));
            types.Add(typeof(EM_Arre));
            types.Add(typeof(EM_Cable));
            types.Add(typeof(EM_Camera));
            types.Add(typeof(EM_CameraMain));
            types.Add(typeof(EM_Culvert));
            types.Add(typeof(EM_ElectronicPosition));
            types.Add(typeof(EM_Erou));
            types.Add(typeof(EM_Fan));
            types.Add(typeof(EM_FireDoor));
            types.Add(typeof(EM_GateAccess));
            types.Add(typeof(EM_Join));
            types.Add(typeof(EM_Line));
            types.Add(typeof(EM_Moin));
            types.Add(typeof(EM_MonitorGas));
            types.Add(typeof(EM_MonitoRgi));
            types.Add(typeof(EM_MonitorWater));
            types.Add(typeof(EM_Net));
            types.Add(typeof(EM_PDA));
            types.Add(typeof(EM_Pump));
            types.Add(typeof(EM_Rtu));
            types.Add(typeof(EM_RtuChannel));
            types.Add(typeof(EM_Service));
            types.Add(typeof(EM_Substation));
            types.Add(typeof(EM_Swit));
            types.Add(typeof(EM_Temfiber));
            types.Add(typeof(EM_Tempmain));
            types.Add(typeof(EM_Term));
            types.Add(typeof(EM_Terminal));
            types.Add(typeof(EM_Trench));
            types.Add(typeof(EM_Tube));
            types.Add(typeof(EM_Tunnel));
            types.Add(typeof(EM_Vent));
            types.Add(typeof(EM_Well));
            types.Add(typeof(EquipmentType));
            types.Add(typeof(FlawPhenomenon));
            types.Add(typeof(PatrolItem));
            types.Add(typeof(SystemDic));
            types.Add(typeof(SystemDicType));
            types.Add(typeof(CableTunnelRel));
            types.Add(typeof(TunnelWellRel));
            types.Add(typeof(Passageway));


            foreach (Type type in types)
            {
                try
                {
                    string listName = "";
                    string entityName = "";
                    int dataType = 0;
                    //获取实体列表名和实体名称
                    object[] attributeArr = type.GetCustomAttributes(typeof(EntityMappingAttribute), false);
                    EntityMappingAttribute attributeMap;
                    if (attributeArr != null && attributeArr.Length == 1)
                    {
                        attributeMap = (EntityMappingAttribute)attributeArr[0];
                        listName = attributeMap.ListName;
                        entityName = attributeMap.EntityName;
                        dataType = attributeMap.DataType;
                    }
                    else
                    {
                        listName = type.Name.ToLower() + "s";
                        entityName = type.Name.ToLower();
                        dataType = 0;
                    }

                    //从xml中获取获取对应实体列
                    XmlNode xnInfos = CommonFunction.GetXmlNode(xmlData,"PdaWrapPackage/" + listName);
                    if (xnInfos == null || xnInfos.ChildNodes.Count == 0)
                        continue;

                    //创建实体列
                    List<Device> deviceList = new List<Device>();
                    List<object> entityList = new List<object>();


                    foreach (XmlNode xnEntity in xnInfos.ChildNodes)
                    {
                        Device device = null;
                        if (dataType == 0)
                        {
                            //创建设备通用实体
                            device = new Device();
                            //获取设备实体属性对应的主站实体列名
                            foreach (PropertyInfo proInfo in typeof(Device).GetProperties())
                            {
                                string colName;
                                attributeArr = proInfo.GetCustomAttributes(typeof(EntityMappingAttribute), false);
                                if (attributeArr != null && attributeArr.Length == 1)
                                {
                                    attributeMap = (EntityMappingAttribute)attributeArr[0];
                                    colName = attributeMap.ColumnName;
                                }
                                else
                                {
                                    colName = proInfo.Name.ToUpper();
                                }

                                //获取对应属性的值
                                XmlNode xnValue = xnEntity.SelectSingleNode(colName);

                                //设置实现属性
                                try
                                {
                                    if (xnValue != null)
                                        proInfo.SetValue(device, xnValue.InnerXml, null);
                                }
                                catch (Exception e) 
                                {

                                }
                            }
                        }

                        //创建对应的实体
                        object entity = Activator.CreateInstance(type);

                        //获取实体属性对应的主站实体列名,获取值并赋予实体
                        foreach (PropertyInfo proInfo in type.GetProperties())
                        {
                            string colName;
                            attributeArr = proInfo.GetCustomAttributes(typeof(EntityMappingAttribute), false);
                            if (attributeArr != null && attributeArr.Length == 1)
                            {
                                attributeMap = (EntityMappingAttribute)attributeArr[0];
                                colName = attributeMap.ColumnName;
                            }
                            else
                            {
                                colName = proInfo.Name.ToLower();
                            }

                            //获取对应属性的值
                            XmlNode xnValue = xnEntity.SelectSingleNode(colName);

                            //设置实现属性
                            try
                            {
                                if (xnValue != null)
                                {
                                    switch (proInfo.PropertyType.Name)
                                    {
                                        case "Int32":
                                            proInfo.SetValue(entity,int.Parse(xnValue.InnerXml), null);
                                            break;
                                        case "DateTime":
                                            proInfo.SetValue(entity, DateTime.Parse(xnValue.InnerXml), null);
                                            break;
                                        default:
                                            proInfo.SetValue(entity, xnValue.InnerXml, null);
                                            break;
                                    }
                                }
                            }
                            catch (Exception e) 
                            {

                            }

                        }

                        //实体添加到列表中
                        if (dataType == 0)
                            deviceList.Add(device);

                        entityList.Add(entity);
                    }

                    //序列化实体列，然后保存实体列表的二进制流到零时文件
                    string guid = Guid.NewGuid().ToString();
                    CompactFormatterPlus cfp = new CompactFormatterPlus();
                    if (dataType == 0)
                    {
                        //设备数据
                        byte[] devicesBuf = cfp.Serialize(deviceList);
                        byte[] deviceDetailsBuf = cfp.Serialize(entityList);
                        CreateDeviceTempFile(guid, devicesBuf, deviceDetailsBuf);
                    }
                    else
                    {
                        //标准数据
                        byte[] standardDataBuf = cfp.Serialize(entityList);
                        CreateStandardTempFile(guid, standardDataBuf);
                    }
                    re += ";" + entityName + "," + guid + "," + entityList.Count.ToString() + "," + dataType.ToString();

                }
                catch(Exception e) 
                {
                    //处理某一类型设备出错
                    //记录日志
                }
            }

            if (re != "")
                re = re.Remove(0, 1);
            return re;
        }

        /// <summary>
        /// 分析GIS数据
        /// </summary>
        /// <param name="xmlData"></param>
        /// <returns></returns>
        private string AnalyseGISData(XmlDocument xmlData)
        {
            string returnStr = "" ;
            XmlNode xnAllGIS = CommonFunction.GetXmlNode(xmlData, "PdaWrapPackage/gisCutAreaDatas");
            if (xnAllGIS == null)
                return "";

            //可能存在多个切图数据
            List<DeviceGPS> deviceGPSList = new List<DeviceGPS>();
            foreach (XmlNode xnGIS in xnAllGIS)  
            {
                XmlNode xnGISData = xnGIS.SelectSingleNode("fgisareagis");
                if (xnGISData == null)
                    continue;

                //切图数据是按Base64编码存储的，先解码出来
                string gisDataStr = CommonFunction.Base64StringToString(xnGISData.InnerText);

                XmlDocument xmlGISData = new XmlDocument();
                xmlGISData.LoadXml(gisDataStr);

                
                XmlNode xnDevices = CommonFunction.GetXmlNode(xmlGISData, "dataset");
                if (xnDevices == null)
                    return "";

                foreach (XmlNode xnDevice in xnDevices)
                {
                    //读取每个设备经纬度信息
                    string device;
                    XmlNode xnDeviceID = xnDevice.SelectSingleNode("devid");
                    if (xnDeviceID == null)
                        continue;

                    string deviceCode = xnDeviceID.InnerText ;
                    //如果数据已经存在，则读取下一个
                    if(deviceGPSList.Where(t=>t.DeviceCode == deviceCode).FirstOrDefault() != null)
                        continue ;

                    string gpsInfo = "";
                    XmlNodeList xnlGPSList = xnDevice.SelectNodes("coor84");
                    foreach (XmlNode  xnlGPS in xnlGPSList)
                    {
                        gpsInfo += "|" + DisposeGPSDegree(xnlGPS.InnerText);
                    }
                    if (gpsInfo != "")
                        gpsInfo = gpsInfo.Remove(0, 1);

                    string localGPSInfo = "";
                    XmlNodeList xnlLocalGPSList = xnDevice.SelectNodes("coor_df");
                    foreach (XmlNode xnlLocalGPS in xnlLocalGPSList)
                    {
                        localGPSInfo += "|" + DisposeGPSDegree(xnlLocalGPS.InnerText);
                    }
                    if (localGPSInfo != "")
                        localGPSInfo = localGPSInfo.Remove(0, 1);



                    //创建设备经纬度实体
                    DeviceGPS deviceGPS = new DeviceGPS();
                    deviceGPS.DeviceGPSID = deviceCode;
                    deviceGPS.DeviceCode = deviceCode;
                    deviceGPS.DeviceType = xnDevice.Name;
                    deviceGPS.GPSInfo = gpsInfo;
                    deviceGPS.LocalGPSInfo = localGPSInfo;
                    deviceGPSList.Add(deviceGPS) ;
                }
            }

            //如果有数据，则序列化成流，并存储数据
            if (deviceGPSList.Count > 0)
            {
                string guid = Guid.NewGuid().ToString();
                CompactFormatterPlus cfp = new CompactFormatterPlus();
                byte[] deviceGPSListBuf = cfp.Serialize(deviceGPSList);
                CreateDeviceGPSTempFile(guid, deviceGPSListBuf);
                returnStr += "GISData," + guid + "," + deviceGPSList.Count.ToString() + ",2" ;

            }

            return returnStr;


        }

        /// <summary>
        /// 处理设备经纬度精度,保留小数点后5位
        /// </summary>
        /// <param name="gpsInfo"></param>
        /// <returns></returns>
        private string DisposeGPSDegree(string gpsInfo)
        {
            string re = "" ;
            string[] pointInfos = gpsInfo.Split(';') ;
            foreach (string pointInfo in pointInfos)
            {
                string[] datas = pointInfo.Split(',');
                if (datas.Length == 2)
                {
                    double x ;
                    double y ;
                    if (double.TryParse(datas[0], out x) && double.TryParse(datas[1], out y))
                    {
                        re += ";" + x.ToString("F5") + "," + y.ToString("F5");
                    }
                }
            }

            if (re != "")
                re = re.Remove(0, 1);

            return re;
        }

        /// <summary>
        /// 创建设备数据的临时文件
        /// </summary>
        /// <param name="guid"></param>
        private void CreateDeviceTempFile(string guid, byte[] devicesBuf, byte[] deviceDetailsBuf)
        {
            try
            {
                string devicesFile = CommonFunction.GetLocalPath() + "\\Temp\\" + guid + ".d";
                FileStream fs = new FileStream(devicesFile, FileMode.Create);
                fs.Write(devicesBuf, 0, devicesBuf.Length);
                fs.Flush();
                fs.Close();

                string deviceDetailsFile = CommonFunction.GetLocalPath() + "\\Temp\\" + guid + ".dd";
                fs = new FileStream(deviceDetailsFile, FileMode.Create);
                fs.Write(deviceDetailsBuf, 0, deviceDetailsBuf.Length);
                fs.Flush();
                fs.Close();
            }
            catch (Exception e)
            {
                throw new Exception("创建设备临时文件失败：" + e.Message);
            }

        }

        /// <summary>
        /// 创建标准数据的临时文件
        /// </summary>
        /// <param name="guid"></param>
        private void CreateStandardTempFile(string guid, byte[] buffer)
        {
            try
            {
                string fileName = CommonFunction.GetLocalPath() + "\\Temp\\" + guid + ".s";
                FileStream fs = new FileStream(fileName, FileMode.Create);
                fs.Write(buffer, 0, buffer.Length);
                fs.Flush();
                fs.Close();
            }
            catch (Exception e)
            {
                throw new Exception("创建标准数据临时文件失败：" + e.Message);
            }

        }

        /// <summary>
        /// 创建设备经纬度的临时文件
        /// </summary>
        /// <param name="guid"></param>
        /// <param name="buffer"></param>
        private void CreateDeviceGPSTempFile(string guid, byte[] buffer)
        {
            try
            {
                string fileName = CommonFunction.GetLocalPath() + "\\Temp\\" + guid + ".g";
                FileStream fs = new FileStream(fileName, FileMode.Create);
                fs.Write(buffer, 0, buffer.Length);
                fs.Flush();
                fs.Close();
            }
            catch (Exception e) 
            {
                throw new Exception("创建设备经纬度临时文件失败：" + e.Message);
            }

        }





        public string UnZipString(string base64Str)
        {
            string returnStr = "";
            byte[] bContent = Convert.FromBase64String(base64Str);

            using (MemoryStream stream = new MemoryStream(bContent))
            {
                ZipInputStream zipstream = new ZipInputStream(stream);
                ZipEntry entry = zipstream.GetNextEntry();
                int readlength;
                byte[] buff = new byte[1024];

                using (MemoryStream outputStream = new MemoryStream())
                {
                    while (true)
                    {
                        readlength = zipstream.Read(buff, 0, buff.Length);
                        outputStream.Write(buff, 0, readlength);

                        if (readlength <= 0)
                        {
                            break;
                        }
                    }

                    outputStream.Position = 0;
                    using (StreamReader reader = new StreamReader(outputStream))
                    {
                        returnStr = reader.ReadToEnd();
                    }
                }
            }
            return returnStr;
        }
    }
}
